package net.takela.common.webflux.security;

import net.takela.common.webflux.security.exception.AppSecurityExceptionHandler;
import net.takela.common.webflux.security.filter.*;
import net.takela.common.webflux.security.filter.AppAuthenticationWebFilter;
import net.takela.common.webflux.security.filter.AppRequestParamSignAuthFilter;
import net.takela.common.webflux.security.filter.ReactiveAuthenticationFilter;
import net.takela.common.webflux.security.filter.ReactiveRequestParamSignFilter;
import net.takela.common.webflux.security.handler.AppAuthorizationManager;
import net.takela.common.webflux.security.handler.JwtSecurityContextRepository;
import net.takela.common.webflux.security.service.AuthTokenManager;
import net.takela.common.webflux.security.service.UserDetailServiceImpl;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.web.server.context.ServerSecurityContextRepository;
import org.springframework.web.server.WebFilter;

/**
 * @author zhangyinghui
 * create at 2023/7/11
 */
@Configuration
public class WebfluxSecurityAutoConfig {


    @Bean
    @ConfigurationProperties(prefix="auth.spring-security")
    /**
     * 
     */
    public SecurityConfigProperties securityConfigProperties(){
        return new SecurityConfigProperties();
    }
    
    /**
     * 
     */
    @Bean
    @ConditionalOnMissingBean(ServerSecurityContextRepository.class)
    public ServerSecurityContextRepository serverSecurityContextRepository(AuthTokenManager authTokenManager){
        return new JwtSecurityContextRepository(authTokenManager);
    }
    
    /**
     * 
     */
    @Bean
    @ConfigurationProperties( prefix = "auth.token" )
    public AuthTokenManager authTokenManager() {
        return new AuthTokenManager();
    }
    
    /**
     * 
     */
    @Bean
    public ReactiveAuthorizationManager authorizationManager(SecurityConfigProperties securityConfigProperties){
        return new AppAuthorizationManager(securityConfigProperties);
    }
    @Bean
    @ConditionalOnMissingBean({ReactiveUserDetailsService.class})
    /**
     * 
     */
    public ReactiveUserDetailsService userDetailsService() {
        return new UserDetailServiceImpl();
    }

//    @Bean
//    @Order(Ordered.HIGHEST_PRECEDENCE)
//    public WebFilter cachedFilter(){
//        return new AppCachedWebFilter();
//    }
    @Bean
    @ConditionalOnMissingBean(ErrorWebExceptionHandler.class)
    @Order(-1)
    /**
     * 
     */
    public ErrorWebExceptionHandler errorWebExceptionHandler(){
        return new AppSecurityExceptionHandler();
    }
    
    /**
     * 
     */
    @Bean
    @ConditionalOnMissingBean(ReactiveAuthenticationFilter.class)
    @Order(1)
    public WebFilter authenticationWebFilter(AuthTokenManager authTokenManager, SecurityConfigProperties securityConfigProperties){
        return new AppAuthenticationWebFilter(authTokenManager, securityConfigProperties);
    }
    
    /**
     * 
     */
    @Bean
    @ConfigurationProperties(prefix = "auth.param.sign")
    public RequestParamSignProperties requestParamSignProperties(){
        return new RequestParamSignProperties();
    }
    
    /**
     * 
     */
    @Bean
    @ConditionalOnMissingBean(ReactiveRequestParamSignFilter.class)
    @Order(1)
    public WebFilter requestParamSignWebFilter(RequestParamSignProperties requestParamSignProperties){
        return new AppRequestParamSignAuthFilter(requestParamSignProperties);
    }
}
